package model;

import java.io.File;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;

import model.contents.Content;
import model.inventory.InventoryPlayer;
import model.time.PlaylistRecordRestriction;
import util.LoggingUtils;
import util.PlayerUtilities;

public class PlaylistRecord implements Playable, Comparable<PlaylistRecord> {
	private int id;
	private int playlistID;
	private int pageID;
	private int containerID;
	private int contentID;
	private int pauseTime;
	private int transition;
	private String	transitionType;
	private int order;

	private boolean clear;
	private boolean displayEventAfter;
	private boolean active;

	private PlaylistRecordRestriction restriction;

	private Content content;
	private Container container;
	//RBB

	// For priority playlist ...............
	private String playlistType;
	private int scheduleTime;
	private String playmethod;

	// -------------------------------------------

	protected final String className = this.getClass().getName();

	//public PlaylistRecord(int id, int playlistId, int pageId, int containerId, int contentId, int pauseTime,
	//		boolean clear, boolean displayEvent, int order, boolean active, int transition,
	//		PlaylistRecordRestriction restriction) {
	public PlaylistRecord(int id, int playlistId, int pageId, int containerId, int contentId, int pauseTime,
			boolean clear, boolean displayEvent, int order, boolean active, int transition,
			PlaylistRecordRestriction restriction,String playlistType,int scheduleTime, String plmethod) {	
		this.id = id;
		this.playlistID = playlistId;
		this.pageID = pageId;
		this.containerID = containerId;
		this.contentID = contentId;
		this.pauseTime = pauseTime;
		this.clear = clear;
		this.displayEventAfter = displayEvent;
		this.order = order;
		this.active = active;
		this.transition = transition;
		this.transitionType   =  "Normal";
		this.restriction = restriction;

		// for priority playlist :)
		this.playlistType 		= playlistType;
		this.scheduleTime 	= scheduleTime;
		this.playmethod		=	plmethod;

	}

	public static List<PlaylistRecord> getPlaylistRecordListFromCSVFile(String fileName) {

		String classMethod = "PlaylistRecord .getPlaylistRecordListFromCSVFile(String fileName)";

		List<PlaylistRecord> records = new ArrayList<PlaylistRecord>();

		if (!new File(fileName).exists()) {
			return records;
		}
		List<String[]> csvData = PlayerUtilities.getArrayFromCSVFile(fileName);
		String[] fields = csvData.remove(0);

		for (String[] recordData : csvData) {
			int id = 0;
			int playlistID = 0;
			int pageID = 0;
			int containerID = 0;
			int contentID = 0;
			int pauseTime = 0;
			int transition = 0;
			int order = 0;

			boolean clear = false;
			boolean displayEventAfter = false;
			boolean active = true;
			boolean isValidRecord = false;

			// for priority playlist ---------
			String playlisttype = "Sequence";
			int scheduletime = 0;
			String plmethod = "settime";
			// ---------------------

			String fromTime = null;
			String toTime = null;
			String fromDate = null;
			String toDate = null;
			String days = null;

			// loop through each row and fetch record data
			for (int i = 0; i < fields.length; i++) {
				String field = fields[i];
				try {
					if (field.equals("playlist_record_id")) {
						isValidRecord = true;
						id = Integer.parseInt(recordData[i]);
					} else if (field.equals("playlist_id")) {
						isValidRecord = true;
						playlistID = Integer.parseInt(recordData[i]);
					} else if (field.equals("page_id")) {
						pageID = Integer.parseInt(recordData[i]);
					} else if (field.equals("container_id")) {
						containerID = Integer.parseInt(recordData[i]);
					} else if (field.equals("content_id")) {
						contentID = Integer.parseInt(recordData[i]);
					} else if (field.equals("duration")) {
						pauseTime = Integer.parseInt(recordData[i]);
					} else if (field.equals("transition")) {
						transition = Integer.parseInt(recordData[i]);
					} else if (field.equals("record_order")) {
						order = pageID = Integer.parseInt(recordData[i]);
					} else if (field.equals("clear")) {
						clear = recordData[i].equals("1") ? true : false;
					} else if (field.equals("displayeventafter")) {
						displayEventAfter = recordData[i].equals("1") ? true : false;
					} else if (field.equals("active")) {
						active = recordData[i].equals("1") ? true : false;
					} else if (field.equals("playlistType")) {					// for priority playlist
						playlisttype = recordData[i];
					} else if (field.equals("play_every")) {					// for priority playlist
						scheduletime = Integer.parseInt(recordData[i]);
					}else if (field.equals("method")) {					// for priority playlist
						plmethod = recordData[i];
					}else if (field.equals("from_date")) {
						fromDate = recordData[i];
					} else if (field.equals("to_date")) {
						toDate = recordData[i];
					} else if (field.equals("from_time")) {
						fromTime = recordData[i];
					} else if (field.equals("to_time")) {
						toTime = recordData[i];
					} else if (field.equals("days")) {
						days = recordData[i];
					} else {
						System.err.println("invalid container field: " + field);
					}
				} catch (NumberFormatException ex) {
					isValidRecord = false;
					System.out.println("invalid data format from source file.");
					ex.printStackTrace();
					LoggingUtils.logStart(classMethod);
					LoggingUtils.log(Level.SEVERE,ex.getMessage()+" invalid data format from source file. "+classMethod,ex);
				}
				catch(ArrayIndexOutOfBoundsException ax)
				{
					LoggingUtils.logStart(classMethod);
					LoggingUtils.log(Level.SEVERE,ax.getMessage()+" " + classMethod,ax);
				}
				catch(NullPointerException nu)
				{
					LoggingUtils.log(Level.SEVERE,nu.getMessage()+" " + classMethod,nu);
				}
			}

			if (isValidRecord && fromTime != null && toTime != null && fromDate != null && toDate != null
					&& days != null) {
				DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				Date from = null;
				Date to = null;
				try {
					from = formatter.parse(fromDate + " " + fromTime);
					to = formatter.parse(toDate + " " + toTime);
					Calendar calFrom = Calendar.getInstance();
					Calendar calTo = Calendar.getInstance();
					calFrom.setTime(from);
					calTo.setTime(to);
					PlaylistRecordRestriction restriction = new PlaylistRecordRestriction(calFrom, calTo,
							days.split(","));

					//PlaylistRecord r = new PlaylistRecord(id, playlistID, pageID, containerID, contentID, pauseTime,
					//clear, displayEventAfter, order, active, transition, restriction);
					// for priority playlist ------------
					PlaylistRecord r = new PlaylistRecord(id, playlistID, pageID, containerID, contentID, pauseTime,
							clear, displayEventAfter, order, active, transition, restriction,playlisttype,scheduletime,plmethod);
					records.add(r);
				} catch (ParseException e) {
					LoggingUtils.log(Level.SEVERE,e.getMessage(),e);
				}
				catch(NullPointerException nu)
				{
					LoggingUtils.log(Level.SEVERE,nu.getMessage(),nu);
				}
			}
		}
		return records;
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return this.id;
	}

	/**
	 * @return the playlistID
	 */
	public int getPlaylistID() {
		return this.playlistID;
	}

	/**
	 * @return the pageID
	 */
	public int getPageID() {
		return this.pageID;
	}

	/**
	 * @return the containerID
	 */
	public int getContainerID() {
		return this.containerID;
	}

	/**
	 * @return the contentID
	 */
	public int getContentID() {
		return this.contentID;
	}

	/**
	 * @return the pauseTime
	 */
	public int getPauseTime() {
		return this.pauseTime;
	}

	/**
	 * @return the transition
	 */
	public int getTransition() {
		return this.transition;
	}

	/**
	 * @return the order
	 */
	public int getOrder() {
		return this.order;
	}

	/**
	 * @return the clear
	 */
	public boolean isClear() {
		return this.clear;
	}

	/**
	 * @return the displayEventAfter
	 */
	public boolean isDisplayEventAfter() {
		return this.displayEventAfter;
	}

	/**
	 * @return the active
	 */
	public boolean isActive() {
		//System.out.println("IS ACTIVE"+this.active);
		return this.active;
	}

	/**
	 * @return the restriction
	 */
	public PlaylistRecordRestriction getRestriction() {
		return this.restriction;
	}

	// for priority playlist --------------

	public String getPlaylistType() {
		return playlistType;
	}

	public void setPlaylistType(String playlistType) {
		this.playlistType = playlistType;
	}

	public int getScheduleTime() {
		return scheduleTime;
	}

	public void setScheduleTime(int scheduleTime) {
		this.scheduleTime = scheduleTime;
	}

	public String getPlaymethod() {
		return playmethod;
	}

	public void setPlaymethod(String playmethod) {
		this.playmethod = playmethod;
	}

	// -----------------------------------

	@Override
	public String toString() {
		// return String.format("id: %-7d order: %-4d pause: %-6d",
		// this.getId(), this.getOrder(), this.getPauseTime());
		return "REC[" + this.getId() + "]";
	}

	public String getLongString() {
		return String.format("id: %-7d order: %-4d pause: %-6d", this.getId(), this.getOrder(), this.getPauseTime());
	}

	@Override
	public int compareTo(PlaylistRecord pr) {
		if (this.isActive() && !pr.isActive()) {
			return -1;
		} else if (!this.isActive() && pr.isActive()) {
			return 1;
		} else if (this.isActive() && pr.isActive()) {

			if (this.getOrder() - pr.getOrder() == 0) {
				return (this.getId() - pr.getId());
			} else {
				return this.getOrder() - pr.getOrder();
			}

			// Implementing area wise playlist ----------------

			/*if(this.getContainerID() - pr.getContainerID() == 0)
			{
				return this.getOrder() - pr.getOrder();
			}
			else
			{
				return this.getContainerID() - pr.getContainerID();
			}*/


		} else {
			return 0;
		}
	}

	@Override
	public int hashCode() {
		return this.getId();
	}

	@Override
	public boolean equals(Object o) {
		if (o instanceof PlaylistRecord) {
			PlaylistRecord p = (PlaylistRecord) o;
			if (p.id == this.id) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean play() {
		//System.out.println("FROM PLAYLIST RECORD");
		//FeaturePlayer.getInstance().play();
		String classMethod = className + ".play()";
		LoggingUtils.logStart(classMethod);
		if (this.isPlayableNow()) {
			System.out.println(String.format("Playing record #%d(%s) in %s(level:%d), pause for %d seconds", 
					this.getId(), this.getContent().getLocalPath(), this.getContainer().getName(), this.getContainer()
					.getDepth(), this.getPauseTime()));
			// set the content for the container
			PlayerUtilities.setVideoPasueTime(this.getPauseTime());
			//------------
			assert (this.getContainer() != null && this.getContent() != null);
			this.getContainer().setTransition(this.getTransition());

			if(this.getTransitionType() == null || this.getTransitionType().equals(""))
				this.getContainer().setTransitionType("Normal");

			this.getContainer().setContent(this.getContent());
			//System.out.println("---------------------------------"+this.getContent().getType());


			synchronized (Player.getInstance()) {
				try {
					if (!Preference.getInstance().isZeroPauseTime()) {
						// Thread.sleep(this.getPauseTime() * 1000);
						int pauseTime = this.getPauseTime() * 1000;

						// Pause time is passing for video pause time


						if (pauseTime <= 0)
						{
							pauseTime = 1;
						}
						Player.getInstance().wait(pauseTime);

					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block

					LoggingUtils.logStart(classMethod);
					LoggingUtils.log(Level.SEVERE,e.getMessage(),e);

					//e.printStackTrace();
				}
			}

			if (this.isClear()) {
				this.container.setContent(null);
			}

			/*if(!this.isClear())
			{
				if(this.getContentID() == 101239)
				{
					this.container.setContent(null);
				}
			}*/

			this.getContainer().setTransition(-1);
			if (this.displayEventAfter) {
				InventoryPlayer.getInstance().play();
			}
			LoggingUtils.logEnd(classMethod + " with a successful play of a playable record " + this.getId());
			return true;
		} else {
			
			PlayerUtilities.setExpireContainerContentValue(this.getContainer().getName());
			if(PlayerUtilities.getExpireContainerContent().get(this.getContainer().getName()) >= PlayerUtilities.getContainerContent().get(this.getContainer().getName()))
			{
				this.container.setContent(null);
				PlayerUtilities.getExpireContainerContent().remove(this.getContainer().getName());
			}
			
			LoggingUtils.logEnd(classMethod + " without a successful play because record " 	+ this.getId() + " is not playable");
			return false;
		}
	}

	public boolean isPlayableNow() {
		//System.out.println("FROM PLAYABLE PLAYLIST RECORD");
		/*
		System.out.println("VALID CONTENT ? "+this.content.isValidContent());
		System.out.println("CONTENT TYPE ? "+this.content.getType());
		System.out.println("CONTAINER ID ? "+this.container.getId());
		System.out.println("RESTICTION ? "+this.restriction.isPlayableNow());
		System.out.println("IS UPDATED ? "+Player.getInstance().isUpdated());
		System.out.println("IS ACtive ? "+this.isActive()); */
		try
		{
			if(this.getPlaymethod().equals("settime"))
			{
				return this.isActive() && this.container != null && this.content != null && this.content.isValidContent()
						&& this.restriction.isPlayableNow() && !Player.getInstance().isUpdated();
			}
			else
			{
				System.out.println("Getting exception");
				return this.isActive() && this.container != null && this.content != null && this.content.isValidContent()
						&& this.restriction.isPlayableNow("recurring") && !Player.getInstance().isUpdated();
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return this.isActive() && this.container != null && this.content != null && this.content.isValidContent()
					&& this.restriction.isPlayableNow() && !Player.getInstance().isUpdated();

		}
	}

	public Content getContent() {
		return this.content;
	}

	public void setContent(Content content) {
		this.content = content;
	}

	public Container getContainer() {
		return this.container;
	}

	public void setContainer(Container container) {
		this.container = container;
	}

	public boolean isExpired() {
		return this.restriction.isExpired();
	}

	public void setContainerID(int containerID) {
		this.containerID = containerID;
	}

	public void setClear(boolean clear) {
		this.clear = clear;
	}

	public String getTransitionType() {
		return transitionType;
	}

	public void setTransitionType(String transitionType) {
		this.transitionType = transitionType;
	}

}
